package com.gen.generator.util;

import com.gen.generator.config.CodeGenConfig;
import com.gen.generator.ui.RightCodeGenDialog;
import com.intellij.database.model.*;
import com.intellij.database.psi.DbColumn;
import com.intellij.database.psi.DbTable;
import com.intellij.database.util.DasUtil;
import com.intellij.psi.PsiElement;
import com.intellij.util.containers.JBIterable;

import java.sql.*;
import java.util.*;

public class DBUtil {

    public  static Map<String, Object> pkColumn = new HashMap<>();

    public static Connection open(String host, String port, String db, String user, String pass) throws Exception {
        String url = String.format("jdbc:mysql://%s:%s/%s?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8",
                host, port, db);
        Class.forName("com.mysql.cj.jdbc.Driver");
        return DriverManager.getConnection(url, user, pass);
    }
    public static List<Map<String, Object>> getTableColumns(CodeGenConfig config) throws Exception {

        String host = config.getHost();
        String port = config.getPort();
        String dbName = config.getDbName();
        String username = config.getUsername();
        String password = config.getPassword();
        String tableName = config.getTableName();
        List<Map<String, Object>> columns = new ArrayList<>();
        Set<String> primaryKeys = new HashSet<>();
        String url = "jdbc:mysql://" + host + ":" + port + "/" + dbName + "?useSSL=false&characterEncoding=UTF-8";

        Class.forName("com.mysql.cj.jdbc.Driver");
        try (Connection conn = DriverManager.getConnection(url, username, password)) {
            DatabaseMetaData metaData = conn.getMetaData();
            // 获取主键信息
            try (ResultSet pkRs = metaData.getPrimaryKeys(null, null, tableName)) {
                while (pkRs.next()) {
                    primaryKeys.add(pkRs.getString("COLUMN_NAME"));
                }
            }
            try (ResultSet rs = metaData.getColumns(null, "%", tableName, "%")) {
                while (rs.next()) {
                    String columnName = rs.getString("COLUMN_NAME");
                    String columnType = rs.getString("TYPE_NAME");
                    String remarks = rs.getString("REMARKS");
                    String isNullable = rs.getString("IS_NULLABLE");
                    boolean isPrimaryKey = primaryKeys.contains(columnName);
                    boolean notNull = "NO".equals(isNullable);
                    convertColumns(columnName, columnType, remarks, isPrimaryKey, notNull, columns);
                }
            }
        }
        return columns;
    }

    private static void convertColumns(String columnName, String columnType, String remarks, boolean isPrimaryKey, boolean notNull, List<Map<String, Object>> columns) throws SQLException {
        Map<String, Object> field = new HashMap<>();
        String javaField = toCamelCase(columnName);
        String javaType = mapToJavaType(columnType);
        field.put("javaField", javaField);
        field.put("javaType", javaType);
        field.put("columnComment", remarks);
        field.put("columnName", columnName);
        field.put("query", !isPrimaryKey);
        field.put("insert", !javaField.equals("id") && !javaField.equals("createTime") && !javaField.equals("updateTime"));
        field.put("edit", !isPrimaryKey);
        field.put("required",notNull && !javaField.equals("createTime") && !javaField.equals("updateTime"));
        field.put("isPk", isPrimaryKey ? 1 : 0);
        field.put("queryType", javaType.equals("LocalDateTime") || javaType.equals("Date") ? "BETWEEN" : "EQ");
        field.put("list", !javaField.equals("createTime") && !javaField.equals("updateTime") && !javaField.equals("delFlag"));
        String dictType = "";
        String readConverterExp = "";
        if (remarks != null) {
            if (remarks.contains("(dict:")) {
                int start = remarks.indexOf("(dict:") + 6;
                int end = remarks.indexOf(")", start);
                if (end != -1) {
                    dictType = remarks.substring(start, end);
                }
            } else if (remarks.contains("(enum:")) {
                int start = remarks.indexOf("(enum:") + 6;
                int end = remarks.indexOf(")", start);
                if (end != -1) {
                    readConverterExp = remarks.substring(start, end);
                }
            }
        }
        if (isPrimaryKey) {
            pkColumn = field;
        }
        field.put("dictType", dictType);
        field.put("readConverterExp", readConverterExp);
        columns.add(field);
    }

    public static String mapToJavaType(String dbType) {
        dbType = dbType.toLowerCase();
        if (dbType.contains("char") || dbType.contains("text")) return "String";
        if (dbType.contains("bigint")) return "Long";
        if (dbType.contains("int")) return "Integer";
        if (dbType.contains("decimal") || dbType.contains("numeric")) return "BigDecimal";
        if (dbType.contains("date") || dbType.contains("time")) return "LocalDateTime";
        if (dbType.contains("double")) return "Double";
        if (dbType.contains("float")) return "Float";
        return "String";
    }

    public static String toCamelCase(String columnName) {
        StringBuilder result = new StringBuilder();
        boolean upper = false;
        for (char c : columnName.toCharArray()) {
            if (c == '_' || c == '-') {
                upper = true;
            } else if (upper) {
                result.append(Character.toUpperCase(c));
                upper = false;
            } else {
                result.append(result.length() == 0 ? Character.toLowerCase(c) : c);
            }
        }
        return result.toString();
    }

    public static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }

    public static CodeGenConfig getConfig(DbTable table, RightCodeGenDialog dialog) throws Exception {
        String author = dialog.getAuthor();
        String packageName = dialog.getPackageName();
        boolean tenant = dialog.isTenant();
        String outputPath = dialog.getOutputPath();

        String tableName = table.getName();

        JBIterable<? extends DasColumn> columnList = DasUtil.getColumns(table);
        List<Map<String, String>> templates = YamlUtil.loadTemplates();
        List<Map<String, Object>> columns = new ArrayList<>();
        for (DasColumn column : columnList) {
            String columnName = column.getName();
            String columnType = column.getDasType() != null
                    ? column.getDasType().getSpecification()
                    : "String";
            String remarks = column.getComment();
            Boolean notNull = column.isNotNull();
            DasTableKey primaryKey = DasUtil.getPrimaryKey(table);
            Iterable<String> names = primaryKey.getColumnsRef().names();
            Boolean isPrimaryKey = false;
            for (String name : names) {
                if (name.equals(columnName)) {
                    isPrimaryKey = true;
                    break;
                }
            }
            convertColumns(columnName, columnType, remarks, isPrimaryKey, notNull, columns);
        }
        return CodeGenConfig.builder()
                .author(author)
                .packageName(packageName)
                .tableName(tableName)
                .outputDir(outputPath)
                .templates(templates)
                .tenant(tenant)
                .columns(columns)
                .build();
    }
}
